package com.weijianhuawen.wjblog.common.exception;

import com.weijianhuawen.wjblog.common.enums.ResponseCodeEnum;
import com.weijianhuawen.wjblog.common.utils.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import org.springframework.security.access.AccessDeniedException;
import java.util.Optional;

/**
 * @version: java version 8
 * @Author: weijianhuawen
 * @description: 全局异常处理器
 * @date: 2024-10-15 12:22
 */

@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler({UserException.class})
    @ResponseBody
    public Response<Object> handleUserException(HttpServletRequest request, UserException userException) {
        log.warn("{} request fail, errorCode:{}, errorMessage:{}", request.getRequestURL(), userException.getErrorCode(), userException.getErrorMessage());
        return Response.fail(userException);
    }

    /**
     * 捕获参数校验错误异常
     * @param request 请求
     * @param e 对应的异常
     * @return 失败响应
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseBody
    public Response<Object> handleMethodArgumentNotValidException(HttpServletRequest request, MethodArgumentNotValidException e) {
        //获取异常码
        String errorCode = ResponseCodeEnum.PARAM_NOT_VALID.getErrorCode();
        //获取校验结果
        BindingResult bindingResult = e.getBindingResult();

        StringBuilder sb = new StringBuilder();

        Optional.ofNullable(bindingResult.getFieldErrors()).ifPresent(errors -> {
            errors.forEach(error ->
                    sb.append(error.getField())
                            .append(" ")
                            .append(error.getDefaultMessage())
                            .append(", 当前值: ")
                            .append(error.getRejectedValue())
                            .append("';")
            );
        });

        //错误信息
        String errorMessage = sb.toString();
        log.warn("{} request error, errorCode: {}, errorMessage: {}", request.getRequestURL(), errorCode, errorMessage);

        return Response.fail(errorCode, errorMessage);
    }

    /**
     * 捕获参数校验异常（Precondition）
     * @param request 请求
     * @param e 对应的异常
     * @return 失败响应
     */
    @ExceptionHandler({IllegalArgumentException.class})
    @ResponseBody
    public Response<Object> handleIllegalArgumentException(HttpServletRequest request, IllegalArgumentException e) {
        log.warn("{} request error, errorCode: {}, errorMessage: {}", request.getRequestURL(), ResponseCodeEnum.PARAM_NOT_VALID.getErrorCode(), e.getMessage());
        return Response.fail(ResponseCodeEnum.PARAM_NOT_VALID.getErrorCode(), e.getMessage());
    }

    /**
     * 鉴权失败异常捕获
     * @param e 鉴权失败异常
     * @throws AccessDeniedException
     */
    @ExceptionHandler({AccessDeniedException.class})
    public void throwAccessDeniedException(AccessDeniedException e) throws AccessDeniedException {
        // 捕获到鉴权失败异常，主动抛出，交给 RestAccessDeniedHandler 去处理
        log.info("============= 捕获到 AccessDeniedException");
        throw e;
    }

    /**
     * 业务异常
     * @param e
     */
    @ExceptionHandler({BizException.class})
    @ResponseBody
    public Response<Object> throwBizException(BizException e) {
        //捕获到业务异常
        log.info("======捕获到业务异常=======");
        return Response.fail(e.getExceptionCode(), e.getExceptionMessage());
    }
}
